package com.apes.fn.server.productRequire;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.repository.LossQuotationRepository;
import com.apes.fn.server.productRequire.impl.AbstractProductRequireDataConversion;
import com.apes.fn.server.productRequire.impl.ProductRequireDataConversionImp;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.util.MapUtil;
import com.apes.pi.service.PiManager;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.service.StoreService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.ProductUom;
import com.apes.scm.masterdata.product.repository.ProductUomRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.google.common.util.concurrent.AtomicDouble;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Service("productRequireService")
public class ProductRequireService extends DomainService {
    @Autowired
    private ProductRequireExpandRepository productRequireExpandRepository;
    @Autowired
    private ProductRequireRepository productRequireRepository;
    @Autowired
    private ProductRequireItemRepository productRequireItemRepository;
    @Autowired
    private ProductAccountService productAccountService;
    @Autowired
    private PiManager piManager;
    @Autowired
    private ProductUomRepository productUomRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private PurchaseOrderRepository purchaseOrderRepository;
    @Autowired
    private StoreService storeService;
    @Autowired
    private MongoTemplate mongoTemplate;


    /** 创建 */
    public ProductRequire create(SimpleRequest request) {
        ProductRequire productRequire = request.getO(ProductRequire.class);

        checkDataValid(productRequire);
        productRequire.setState("create");
        productRequire.setCreateDate(new Date());

        // 主表缺失数据赋值
        this.evaluationRequire(productRequire);

        productRequire.getProductRequireItems().forEach(requireItem -> {
            // 明细缺失数据赋值
            this.evaluationRequireItem(requireItem);
        });

        productRequire = productRequireRepository.saveAndFlush(productRequire);
        setProductRequireBilling(productRequire, 1.00, "要货单创建");
        return productRequire;
    }

    private void evaluationRequire(ProductRequire require) {
        if (require.getPlatform() == null) {
            require.setPlatform(SpringManager.getBean(PartyRoleRepository.class).findOne("1001"));
        }
    }

    private void evaluationRequireItem(ProductRequireItem requireitem) {
        if (StringUtils.isEmpty(requireitem.getProductRequire().getSource())) {
            requireitem.setSourceState(SpringManager.getBean(EnumerationRepository.class).findOne("003334"));
        }
    }

    public void save(ProductRequire require) {
        productRequireRepository.save(require);
    }



    /** 修改 */
    public ProductRequire update(SimpleRequest request) {
        ProductRequire oldProductRequire = (ProductRequire) isValid(request, productRequireRepository);
        ProductRequire productRequire = request.getO(ProductRequire.class);

        // 要货数量先减少后增加
        setProductRequireBilling(oldProductRequire, -1.00, "要货单修改");
        setProductRequireBilling(productRequire, 1.00, "要货单修改");

        checkDataValid(productRequire);

        return productRequireRepository.saveAndFlush(productRequire);
    }


    /** 删除 */
    public String delete(SimpleRequest request) {
        ProductRequire productRequire = request.getO(ProductRequire.class);
        productRequire.setState("delete");
        productRequire.setDeleteId(getPerson(request));
        productRequire.setDeleteDate(new Date());

        // 释放要货数量
        setProductRequireBilling(productRequire, -1.00, "要货单删除");

        productRequireRepository.saveAndFlush(productRequire);
        return "删除成功";
    }


    /** 查询单个数据 */
    public ProductRequire findOne(SimpleRequest request) {
        String id = "";
        if (request.getMap().size() != 0) {
            try {
                id = request.get("id");
            } catch (Exception e) {
                id = request.get("ID");
            }
        } else {
            id = request.getMap().get("ID").toString();
        }

        ProductRequire productRequire = productRequireRepository.findOne(id);
        if (productRequire == null) throw new RuntimeException("要货单：" + request.get("id") + " 在系统中不存在。");
        return productRequire;
    }


    // 审核
    public ProductRequire approve(SimpleRequest request) {
        ProductRequire productRequire = request.getO(ProductRequire.class);
        storeService.judgeFCKBJ(productRequire.getLocation());
        int iZKXZBJ = productRequire.getZKXZBJ();
        productRequire = productRequireRepository.findOne(productRequire.getId());
        productRequire.setState("approve");
        productRequire.setApproveId(getPerson(request) == null ? productRequire.getOperator1() : getPerson(request));
        productRequire.setApproveDate(new Date());
        productRequire.setZKXZBJ(iZKXZBJ);
        productRequire = productRequireRepository.saveAndFlush(productRequire);

        // 转储
        invoke("stock.requireAutoGeneratorOrderService.timeInner", MapUtil.mapper("requireId", productRequire.getId()));

        // 自动生成采购订单
        sendSynEvent("event:requireAutoGeneratorOrderService.autoPurOrder", new JSONObject(MapUtil.mapper("id", productRequire.getId())));

        return productRequire;
    }


    public void batchUpdateStateApprove(SimpleRequest request) {
        List array = request.getJA();
        productRequireRepository.save(array);
    }

    // 锁定
    public void locked(SimpleRequest request) {
        List array = request.getJA();
        productRequireRepository.save(array);
    }

    public void batchUpdateState(List<ProductRequire> requires) {
        productRequireRepository.save(requires);
    }


    /**
     * 功能：查询要货计量单位
     * 采购订单会使用
     */
    public long findRequireUom(SimpleRequest request) {
        ProductRequireItem item = productRequireItemRepository.findOne(request.getJO().getString("id"));
        if (Objects.isNull(item)) return -1L;
        return item.getUom().getId();
    }

    /** 要货终止原因 */
    private void saveTerminationReson(ProductRequireItem requireItem, double cancelQty, PartyRole repealUid) {
        RequireTerminationReson terminationReson = new RequireTerminationReson();
        terminationReson.setProduct(requireItem.getProduct());
        terminationReson.setTerminationReson(requireItem.getTerminationReson());
        terminationReson.setProductRequire(requireItem.getProductRequire());
        terminationReson.setTerminationQty(cancelQty);
        terminationReson.setRepealUid(repealUid);
        terminationReson.setRepealDate(new Date());
        SpringManager.getBean(RequireTerminationResonRepository.class).saveAndFlush(terminationReson);
    }


    /** 终止( 终止其中的几件 或者全部终止 ) */
    public ProductRequire repeal(SimpleRequest request) {
        ProductRequire require = request.getO(ProductRequire.class);
        require.setRepealDate(new Date());
        require.setState("repeal");
        if (require.getRepealId() != null) require.setRepealDate(null);
        if (require.getRepealId() == null) {
            require.setRepealId(request.getPerson()); // 手工做单终止人
        }

        List<String> repealReason = new ArrayList<>();
        require.getProductRequireItems().forEach(requireItem -> {
            double replusQty = requireItem.getQtyRequire() - requireItem.getQtyAssigned() - requireItem.getQtyEnded();
            if (replusQty <= 0) return;
            if (requireItem.getQtyEnd() > replusQty) throw new RuntimeException("现有可终止数量为：" + replusQty);

            // 界面终止可不填本次终止数量
            if (StringUtils.isEmpty(requireItem.getTerminationReson()) && requireItem.getQtyEnd() > 0) throw new RuntimeException("请填写终止原因！");
            if (requireItem.getQtyEnd() == 0) return;
            requireItem.setQtyEnded(requireItem.getQtyEnded() + requireItem.getQtyEnd());

            // 减少要货数量
            productAccountService.setProductRequireBilling(requireItem.getProduct(), require.getLocation(), requireItem.getUom(), -1 * requireItem.getQtyEnd(),
                    require.getInnerBusinessType(), require.getId(), requireItem.getId(), "要货单终止", require.getCompany(), require.getId());

            // 记录要货终止原因信息
            this.saveTerminationReson(requireItem, requireItem.getQtyEnd(), require.getRepealId());

            // 记录日志
            String remark = requireItem.getRemark();
            String content = requireItem.getProduct().getId() + "终止数量：" + requireItem.getQtyEnd();
            if (StringUtils.isEmpty(remark)) content += "，终止原因：" + remark;
            repealReason.add(content);
        });

        // 判断状态
        require.checkComplete();

        // 写入终止日志
        this.writeLog(request, require.getRepealId().getId(), require, repealReason);

        require.setWrite(false); // 这样日志不会写两次
        return productRequireRepository.saveAndFlush(require);
    }

    // 外部调用终止, 提供给服务方案、定损终止
    public void externalRepeal(SimpleRequest request) {
        JSONObject getJO = request.getJO();

        List<ProductRequire> requires = productRequireRepository.findAll(JpaDsl.toCriteriaByEq("source", getJO.getString("source")));
        if (requires.isEmpty()) throw new RuntimeException("未找到有效要货单");

        getJO.getJSONArray("items").forEach(item -> {
            JSONObject itemO = (JSONObject) item;
            double qty = itemO.getDoubleValue("qty");
            String terminationResonId = itemO.getString("terminationResonId");
            if (!StringUtils.hasText(terminationResonId)) throw new RuntimeException("请填写终止原因！");

            // changeFlag : 用来标记要货单是否有变动
            AtomicBoolean changeFlag = new AtomicBoolean(false);
            requires.forEach(require -> {
                if (require.getState().equals("locked")) throw new RuntimeException("要货单正在锁定中, 请稍后再试!");

                require.getProductRequireItems().forEach(requireItem -> {
                    // 获取相同商品
                    if (!itemO.getString("productId").equals(requireItem.getProduct().getId())) return;
                    double surplusEndQty = requireItem.getQtyRequire() - requireItem.getQtyEnd() - requireItem.getQtyAssigned() - requireItem.getOrderQty();

                    // 无终止数据直接返回
                    if (surplusEndQty <= 0) return;
                    changeFlag.set(true);
                    requireItem.setQtyEnd(surplusEndQty > qty?surplusEndQty:qty);
                    requireItem.setTerminationReson(getBean(EnumerationRepository.class).findOne(itemO.getString("terminationResonId")));
                });

                // 修改时间戳
                require.setRepealId(partyRoleRepository.findOne(getJO.getString("operatorId")));
                require.setLastUpdatedStamp(new Date());
                SimpleRequest request1 = new SimpleRequest();
                request1.setData(require);
                this.repeal(request1);
            });
        });
    }

    // 终止 - 手动写入日志
    private void writeLog(SimpleRequest request, String operator, ProductRequire productRequire, List<String> repealReason) {
        User user = request.getCurrentUser()==null?
                userRepository.findAll(JpaDsl.toCriteriaByEq("person.id", operator)).stream().findFirst().get():request.getCurrentUser();
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.create", MapUtil.mapper(
                "businessType", productRequire.getInnerBusinessType(),
                "businessKey", productRequire.getInnerBusinessKey(),
                "workPostName",request.getSession() != null ? request.getSession().getAttribute("workPostName", String.class) : null,
                "operate", "终止", "operator_id", user.getId(),
                "remark", repealReason.stream().reduce("", (d1, d2) -> {
                    if (d1 == null || d1.equals("")) return d2==null?"":d2;
                    return d1 + ";" + d2;
                }, String::concat)
        ));
    }


    // 写入要货数量
    private void setProductRequireBilling(ProductRequire productRequire, Double unit, String remark) {
        productRequire.getProductRequireItems().stream().forEach(productRequireItem -> {
            productAccountService.setProductRequireBilling(
                    productRequireItem.getProduct(), productRequire.getLocation(), productRequireItem.getUom(),
                    unit * productRequireItem.getQtyRequire(),
                    productRequire.getInnerBusinessType(), productRequire.getId(), productRequireItem.getId(), remark,
                    productRequire.getCompany(), productRequire.getId());
        });
    }

    /***
     * 要货单终止,回写定损单明细要货数量
     */
    private void writeBackLossQuotationItem(ProductRequire productRequire) {
        LossQuotationRepository lossQuotationRepository = SpringManager.getBean(LossQuotationRepository.class);
        String source = productRequire.getSource();
        LossQuotation lossQuotation = lossQuotationRepository.findOne(source);
        if (lossQuotation == null) throw new RuntimeException("未找到来源的定损报价单!!!");
        lossQuotation.getLossQuotationItems().stream().forEach(
                lossQuotationItem -> {
                    productRequire.getProductRequireItems().stream().forEach(
                            productRequireItem -> {
                                if (lossQuotationItem.getProduct().getId().equals(productRequireItem.getProduct().getId())) {
                                    Double receiveQty = lossQuotationItem.getReceiveQty();
                                    Double qtyEnded = productRequireItem.getQtyEnded();
                                    if (receiveQty < qtyEnded)
                                        throw new RuntimeException("定损报价单要货数量小于要货单的已终止数量,回写失败!!!商品:"+productRequireItem.getProduct().getName());
                                    if (receiveQty == qtyEnded) {
                                        lossQuotationItem.setReceiveQty(0);
                                        lossQuotationItem.setRequireQty(0);
                                    }else {
                                        lossQuotationItem.setReceiveQty(receiveQty-qtyEnded);
                                        lossQuotationItem.setRequireQty(receiveQty-qtyEnded);
                                    }
                                }
                            }
                    );
                }
        );

        try {
            lossQuotationRepository.saveAndFlush(lossQuotation);
        } catch (Exception e) {
            throw new RuntimeException("更新定损报价单要货数量失败!!!");
        }
    }

    /***
     * 判断当前单据是否完成
     */

    private boolean isDone(ProductRequire productRequire) {
        return !productRequire.getProductRequireItems().stream().anyMatch(productRequireItem ->
                productRequireItem.getQtyRequire() - productRequireItem.getQtyArrive() - productRequireItem.getQtyEnded() > 0
        );
    }

    /***
     * 数据是否合法
     * @param request
     * @param repository
     */
    private Model isValid(SimpleRequest request, CustomRepository repository) {
        Model oldModel = (Model) repository.findOne((String) request.get("id"));
        if (oldModel == null) throw new RuntimeException("订单【" + request.get("id") + "】在系统中不存在。");
        if (oldModel.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        return oldModel;
    }


    // 限制要货单的生成
    private void checkDataValid(ProductRequire productRequire) {
        // 限制商品服务类型唯一
        Map<String, List<ProductRequireItem>> groupByServeType = productRequire.getProductRequireItems().stream().collect(Collectors.groupingBy(
                productRequireItem -> productRequireItem.getProduct().queryServeType().getId()
        ));

        // 生成要货单的商品服务类型
        if (groupByServeType.keySet().size() > 1) {
            throw new RuntimeException("生成要货单的商品服务类型不唯一");
        }

        // 写入要货单的服务类型
        productRequire.setServeType(productRequire.getProductRequireItems().get(0).getProduct().queryServeType());
    }


    /**
     * 冲红更新要货实际订货数量
     * @param simpleRequest
     */
    public void redemptionReductionArriveQty(SimpleRequest simpleRequest) {
        PurchaseOrder purchaseOrder = simpleRequest.getO(PurchaseOrder.class);
        PurchaseOrder originPurchaseOrder = purchaseOrderRepository.findOne(purchaseOrder.getOrigin());
        String productRequireId = originPurchaseOrder.getProductRequire();
        if (productRequireId == null) return;
        ProductRequire productRequire = productRequireRepository.findOne(productRequireId);
        purchaseOrder.getPurchaseItems().forEach(purchaseOrderItem -> {
            productRequire.getProductRequireItems().forEach(productRequireItem -> {
                if (purchaseOrderItem.getProduct().getId().equals(productRequireItem.getProduct().getId())) {
                    productRequireItem.setQtyArrive(productRequireItem.getQtyArrive() - productRequireItem.getUom().computeQty(purchaseOrderItem.getProductUomQty(), productRequireItem.getUom(), true) );
                }
            });
        });
        if ("complete".equals(productRequire.getState())) productRequire.setState("approve");
        productRequireRepository.save(productRequire);
    }

    /**
     * 传入服务方案，获取数量
     * @param request
     * @return
     */
    public List obtainProductRequire(SimpleRequest request){
        JSONObject jo = request.getJO();
        String servicePlanId = jo.getString("servicePlanId");

        List<ProductRequire> productRequires =
                productRequireRepository.findAll(JpaDsl.toCriteriaByEq("source",servicePlanId,"sourceBusinessType","servicePlan"));

        List reList = new ArrayList();
        if(productRequires.size() != 0) {
            reList = productRequires.stream().map(productRequire -> {
                return MapUtil.mapper(
                        "id",productRequire.getId(),
                        "createDate",productRequire.getCreateDate(),
                        "approveDate",productRequire.getApproveDate(),
                        "source",productRequire.getSource(),
                        "locationId",productRequire.getLocation().getId(),
                        "platFormId",productRequire.getPlatform().getId(),
                        "deleteDate",productRequire.getDeleteDate(),
                        "endDate",productRequire.getRepealDate(),
                        "productRequireItem",productRequire.getProductRequireItems().stream().map(productRequireItem -> {
                            return mapper(
                                    "id",productRequireItem.getId(),
                                    "productId",productRequireItem.getProduct().getId(),
                                    "productUonName",productRequireItem.getUom().getName(),
                                    "qtyRequire",productRequireItem.getQtyRequire(),
                                    "qtyEnd",productRequireItem.getQtyEnded()
                            );
                        }).collect(Collectors.toList())
                );
            }).collect(Collectors.toList());
        }
        return reList;
    }

    /**
     * 要货审核查询区域仓库存
     * @param simpleRequest
     * @return
     */
    public JSONObject qryRegionalWarehouseInvetory(SimpleRequest simpleRequest) {
        ProductRequire productRequire = simpleRequest.getO(ProductRequire.class);
        if (productRequire.getLocation().getPhyDepot() == null) return new JSONObject();
        String depotOrigin = productRequire.getLocation().getPhyDepot().getOrigin();
        JSONObject data = new JSONObject();
        String productIdStr = "";
        JSONArray itemArray = new JSONArray();
        JSONObject singleData = new JSONObject();
        for (ProductRequireItem productRequireItem:productRequire.getProductRequireItems()) {
            singleData = new JSONObject();
            String productId = productRequireItem.getProduct().getId();
            productIdStr += "'" + productId + "',";
            singleData.put("PRODUCT_ID", productId);
            singleData.put("PRODUCT_NAME", productRequireItem.getProduct().getName());
            singleData.put("qtyRequire", productRequireItem.getQtyRequire());
            singleData.put("uomName", productRequireItem.getUom().getName());
            itemArray.add(singleData);
        }
        data.put("item", itemArray);
        data.put("LOCATION_ID", productRequire.getLocation().getId());
        data.put("LOCATION_NAME", productRequire.getLocation().getName());
        data.put("productIdStr", productIdStr.substring(0, productIdStr.length() - 1));
        data.put("GSID", "1001".equals(productRequire.getPlatform().getId())?"1001":productRequire.getCompany().getId());
        data.put("DDID", depotOrigin != null?depotOrigin:productRequire.getLocation().getPhyDepot().getId());
        data.put("KQID", productRequire.getLocation().getUsage().getId());

        JSONObject getData = piManager.synErp("scmYhdService.qryQYCKC", data);
        return JSONObject.parseObject(getData.get("obj").toString());
    }


    // 外采要货采购订单终止 - 减少要货到达数量
    public void updateQtyArrive(SimpleRequest simpleRequest) {
        productRequireItemRepository.updateQtyArrive(simpleRequest.get("id"));
    }

    /**
     * 根据App数据生成要货单
     * @return 要货单
     */
    public ProductRequire autoCreateProductRequire(SimpleRequest request) {
        ProductRequire productRequire = this.externalCreate(request).get(0);
        invoke("stock.productRequire.approve", productRequire);
        return productRequire;
    }

    /**
     * 调用回写要货单给App方法
     * @param id
     */
    public void invokeSendToApp(String id) {
        ProductRequire productRequire = productRequireRepository.findOne(id);
        if (productRequire == null) throw new RuntimeException("找不到要货单");
        SimpleRequest request = new SimpleRequest();
        request.setData(productRequire);
        sendToApp(request);
    }

    /**
     * 要货单已完成或全部终止后，发送数据给App
     */
    public void sendToApp(SimpleRequest request) {
        ProductRequire o = request.getO(ProductRequire.class);
        ProductRequire productRequire = productRequireRepository.findOne(o.getId());
        if (productRequire == null) return;
        if (!("materiel".equals(productRequire.getSourceBusinessType()) && "complete".equals(productRequire.getState()))) return;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderNumber",productRequire.getSource());//物料单id
        jsonObject.put("orderStatus","1");//1取消2已完成
        List<JSONObject> list = new ArrayList<>();
        productRequire.getProductRequireItems().forEach(item -> {
            if (item.getQtyArrive() > 0) jsonObject.put("orderStatus","2");
            JSONObject goods = new JSONObject();
            goods.put("goodsCode",item.getProduct().getId());//商品id
            goods.put("realNumber",(int)item.getQtyArrive());//最终数量
            list.add(goods);
        });
        jsonObject.put("goodsInfo",list);
        //发送信息给App
        Map map = MapUtil.mapper(
                "body",jsonObject,
                "headers",MapUtil.mapper(
                        "method","v1/materiel/change-status",
                        "action","post"
                )
        );
        JSONObject result = JSONObject.parseObject(this.invoke("pi.app.ext",map));
        try {
            if(!result.getBoolean("success")){
                throw new RuntimeException("AppError:" + result.toJSONString());
            }
        }catch (Exception e){
            throw new RuntimeException("AppError:" + result.toJSONString());
        }
    }


    public Object query(SimpleRequest request)throws Exception {
        JSONObject jo = request.getJO();
        JSONArray jsonArray = jo.getJSONArray("condition");
        JSONArray array = createCondition();
        Boolean arriveState = false;
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject)o;
            if (jsonObject.getString("field").equals("ARRIVE_STATE")) {
                arriveState = true;
                for (int i = 0; i < jsonObject.getJSONArray("value").size(); i++) {
                    int value = jsonObject.getJSONArray("value").getJSONObject(i).getIntValue("id");
                    if (value == 1) array.getJSONObject(0).put("value", 1);
                    else if (value == 2) array.getJSONObject(1).put("value", 2);
                    else if (value == 3) array.getJSONObject(2).put("value", 3);
                    else if (value == 4) array.getJSONObject(3).put("value", 4);
                }
            }
        }
        if (arriveState) jsonArray.addAll(array);

        return com.apestech.framework.json.JSON.toJSON(jo.toJSONString());
    }

    private JSONArray createCondition() {
        JSONArray jsonArray = new JSONArray();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("field", "ARRIVE_STATE_1");
        jsonObject.put("operator", "EQ");
        jsonObject.put("value", 999);
        jsonArray.add(jsonObject.clone());
        jsonObject.put("field", "ARRIVE_STATE_2");
        jsonArray.add(jsonObject.clone());
        jsonObject.put("field", "ARRIVE_STATE_3");
        jsonArray.add(jsonObject.clone());
        jsonObject.put("field", "ARRIVE_STATE_4");
        jsonArray.add(jsonObject.clone());
        return jsonArray;
    }

    // 自动删除 - 提供给运维用
    public void autoDeleteRequqire() {
        List<Map> cancelRequires = productRequireRepository.canCancelRequire();
        cancelRequires.forEach(require -> {
            Map requireM = require;

            ProductRequire productRequire = productRequireRepository.accordingIdRequire(requireM.get("ID").toString());
            ProductRequire newProductRequire = (ProductRequire) productRequire.clone();
            newProductRequire.setCreator("system");
            newProductRequire.setProductRequireItems(null);
            List<ProductRequireItem> productRequireItems = productRequireItemRepository.qryCanCancelRequire(productRequire.getId());
            productRequireItems.forEach(requireItem -> requireItem.setQtyEnd(requireItem.getQtyRequire() - requireItem.getQtyAssigned() - requireItem.getQtyEnded() - requireItem.getOrderQty()));
            newProductRequire.setProductRequireItems(productRequireItems);
            try {
                invoke("stock.productRequire.delete", newProductRequire);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }


    // 查询要货数量
    @Listener(topic = "event:service.productRequireService.findRequireQty")
    public JSONObject findRequireQty(SimpleRequest request) {
        ProductRequireItem item = productRequireItemRepository.findOne(request.getJO().getString("id"));

        if (Objects.isNull(item)) return new JSONObject();
        return new JSONObject(MapUtil.mapper("qtyRequire", item.getQtyRequire(), "qtyAssigned", item.getQtyAssigned(), "qtyEnded", item.getQtyEnded(), "orderQty", item.getOrderQty()));
    }

    // 采购订单新增 | 删除 - 增加 | 减少订货数量
    @Listener(topic = "event:server.productRequireService.updateOrderQty")
    public void updateOrderQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        ProductRequire require = productRequireRepository.findOne(getJO.getString("id"));

        require.getProductRequireItems().forEach(requireItemObj -> {
            getJO.getJSONArray("item").forEach(requireItem -> {
                JSONObject externalRequireData = (JSONObject) requireItem;
                if (requireItemObj.getId().equals(externalRequireData.getString("id"))) {
                    double qty = requireItemObj.getOrderQty() + externalRequireData.getDoubleValue("qty");
                    requireItemObj.setOrderQty(qty);
                }
            });
        });
        require.setLastUpdatedStamp(new Date());
        productRequireRepository.save(require);
    }

    // 采购订单终止 - 减少要货分配数
    public void updateAssignmentQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        ProductRequire require = productRequireRepository.findOne(getJO.getString("id"));
        String distributionId = getJO.getString("distributionId");

        require.getProductRequireItems().forEach(requireItemObj -> {
            getJO.getJSONArray("item").forEach(requireItem -> {
                JSONObject externalRequireData = (JSONObject) requireItem;
                String rquireItemId = externalRequireData.getString("id");
                double qtyAssigned = externalRequireData.getDoubleValue("qtyAssigned");

                if (requireItemObj.getId().equals(rquireItemId)) {
                    double newQtyAssigned = this.changeQty(distributionId, rquireItemId, require.getId(), qtyAssigned, requireItemObj.getUom());
                    double assignmentQty = requireItemObj.getQtyAssigned() + newQtyAssigned;
                    requireItemObj.setQtyAssigned(assignmentQty);
                }
            });
        });
        require.setLastUpdatedStamp(new Date());
        productRequireRepository.save(require);
    }

    // 采购订单审核 - 增加要货分配数量、减少订货数量
    public void updateAssignmentQtyAndOrderQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        String distributionId = getJO.getString("distributionId");

        ProductRequire require = productRequireRepository.findOne(getJO.getString("id"));
        require.getProductRequireItems().forEach(requireItemObj -> {
            getJO.getJSONArray("item").forEach(requireItem -> {
                JSONObject externalRequireData = (JSONObject) requireItem;
                if (requireItemObj.getId().equals(externalRequireData.getString("id"))) {
                    double orderQty = externalRequireData.getDoubleValue("orderQty");
                    double qtyAssigned = externalRequireData.getDoubleValue("qtyAssigned");

                    double changeOrderQty = this.changeQty(distributionId, requireItemObj.getId(), require.getId(), orderQty, requireItemObj.getUom());
                    double changeAssignQty = this.changeQty(distributionId, requireItemObj.getId(), require.getId(), qtyAssigned, requireItemObj.getUom());


                    double qty = requireItemObj.getOrderQty() + changeOrderQty;
                    double assignmentQty = requireItemObj.getQtyAssigned() + changeAssignQty;
                    requireItemObj.setOrderQty(qty);
                    requireItemObj.setQtyAssigned(assignmentQty);
                }
            });
        });
        require.setLastUpdatedStamp(new Date());
        productRequireRepository.save(require);
    }

    private double changeQty(String distributionId, String requireItemId, String requireId, double qty, ProductUom requireUom) {
        List<ProductRequireExpand> requireExpands = productRequireExpandRepository.findAll(JpaDsl.toCriteriaByEq("distributionId", distributionId, "originItemId", requireItemId, "origin", requireId));
        if (requireExpands.isEmpty()) throw new RuntimeException("未找到扩展表信息， 要货单号：" + requireId + ", 配货单号：" + distributionId + ", 要货明细编码：" + requireItemId);
        if (requireExpands.get(0).getProductUomId().getFactor() == 1) return qty;
        return requireExpands.get(0).getProductUomId().computeQty(qty, requireUom, true);
    }


    @Listener(topic = "event:stock.pick.delivery")
    public void pickUpdateArriveQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        String operation = getJO.getString("operation");
        String originBusinessType = getJO.getString("originBusinessType");
        if ("PurchaseOrder".equals(originBusinessType) && !"receipt".equals(operation)) return;
        List<JSONObject> purchaseOrder = sendSynEvent("event:scm.purchaseService.accordIdFind", MapUtil.mapper("id", getJO.getString("origin")));
        if (purchaseOrder.isEmpty() || StringUtils.isEmpty(purchaseOrder.get(0).getString("productRequire"))) return;

        ProductRequire require = productRequireRepository.findOne(purchaseOrder.get(0).getString("productRequire"));
        JSONArray pickItemArray = getJO.getJSONArray("items");

        for (int i = 0, iLen = pickItemArray.size(); i < iLen; i++) {
            JSONObject pickItemObj = pickItemArray.getJSONObject(i);

            // 需要观察要货跟踪是否有异常???????????????????????????
            // 获取要货明细编码
            List requireItemIds = sendSynEvent("event:scm.purchaseService.accordItemIdFindSourceItemId", MapUtil.mapper("id", pickItemObj.get("originItemId")));
            if (requireItemIds.isEmpty()) continue;

            double qtyDone = pickItemObj.getDoubleValue("qtyDone");
            for (int j = 0, jLen = require.getProductRequireItems().size(); j < jLen; j++) {
                ProductRequireItem requireItem = require.getProductRequireItems().get(j);
                if (requireItem.getId().equals(requireItemIds.get(0))) {
                    double currentNewArriveQty = qtyDone;

                    // 计量单位不一致时以要货单位转换成要货数量
                    if (!requireItem.getUom().isPurchaseFirst()) {
                        ProductUom purchaseUom = productUomRepository.findBypurchaseUom(requireItem.getProduct().getId());
                        currentNewArriveQty = Math.floor(purchaseUom.computeQty(qtyDone, requireItem.getUom(), true));
                    }
                    requireItem.setArriveDate(new Date());
                    requireItem.setQtyArrive(requireItem.getQtyArrive() + currentNewArriveQty);
                    break;
                }
            }
        }

        require.setLastUpdatedStamp(new Date());
        require.checkComplete();
        productRequireRepository.save(require); // 需要观察要货跟踪是否有异常???????????????????????????

    }

    @Listener(topic = "event:fn.crossCompanyTransferNewService.approve")
    public void dumpUpdateAssiveQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        if (StringUtils.isEmpty(getJO.getString("specialDocumentsType")) || !"要货补货转储新逻辑 - 后面要剔除".equals(getJO.getString("specialDocumentsType"))) return;
        List<String> requireIds = Arrays.asList(getJO.getString("requireIds").split(","));

        Map<String, ProductRequire> requireCache = new HashMap();
        getJO.getJSONArray("item").forEach(item -> { // 转储数据
            JSONObject dumpObj = new JSONObject((Map) item);
            
            // 查询缺货要货单
            List<Map> needReplenishmentRequires = productRequireItemRepository.replenishmentManageRequireItem(getJO.getString("locationId"), dumpObj.getString("productId"), requireIds);
            if (needReplenishmentRequires.isEmpty()) return;

            long requireUomId = Long.valueOf(needReplenishmentRequires.get(0).get("PRODUCT_UOM_ID").toString());
            double dumpQtyConvertRequireQty = this.accordUomChangeQty(dumpObj.getDoubleValue("qty"), requireUomId, dumpObj.getLong("uomId"));
            AtomicDouble canAssignQty = new AtomicDouble(dumpQtyConvertRequireQty);

            // 要货缺口明细 - 根据要货单号分组
            needReplenishmentRequires.stream().collect(Collectors.groupingBy(requireGapItem -> {
                return requireGapItem.get("ID").toString();
            })).forEach((k, v) -> {

                // 查找要货单 - 存入缓存结束循环后批量修改
                if (Objects.isNull(requireCache.get(k))) requireCache.put(k, productRequireRepository.findOne(k));

                ProductRequire require = requireCache.get(k);
                require.setLastUpdatedStamp(new Date());
                require.checkComplete();

                // 要货缺口明细循环
                v.forEach(requireItem -> {
                    JSONObject requireItemObj = new JSONObject(requireItem);

                    // 给要货对象赋值
                    require.getProductRequireItems().stream()
                            .filter(rItem -> {return rItem.getProduct().getId().equals(requireItemObj.getString("PRODUCT_ID")) && rItem.getQtyRequire() - rItem.getOrderQty() - rItem.getQtyAssigned() > 0;})
                            .forEach(rItem2 -> {
                                double gapQty = rItem2.getQtyRequire() - rItem2.getOrderQty() - rItem2.getQtyAssigned();
                                double assignQty = canAssignQty.get() > gapQty? gapQty : canAssignQty.get();
                                canAssignQty.set(canAssignQty.get() - assignQty);

                                // 1. 修改要货制单数量，***************【必须先修改要货制单数量，再修改分配数量】***********************
                                this.updateProductRequireBilling(rItem2, getJO.getString("id"), getJO.getString("operateInnerBusinessType"), dumpObj.getString("id"),
                                        getJO.getString("operate"), -1 * rItem2.getCurrentAssigentQty(assignQty));

                                // 2. 修改分配数量
                                rItem2.setQtyAssigned(rItem2.getQtyAssigned() + assignQty);

                                // 3. 写入要货扩展表
                                Map requireExpand = MapUtil.mapper("origin", rItem2.getProductRequire().getId(),
                                        "originItemId", rItem2.getId(),
                                        "originBusinessType", rItem2.getProductRequire().getInnerBusinessType(),
                                        "productId", MapUtil.mapper("id", rItem2.getProduct().getId()),
                                        "productUomId", MapUtil.mapper("id", dumpObj.getLong("uomId")),
                                        "distributionId", getJO.get("id"),
                                        "requireQty", rItem2.getQtyRequire(),
                                        "assignQty", assignQty);
                                invoke("stock.productRequireExpand.save", requireExpand);
                    });

                });
            });

        });

        requireCache.forEach((k, v) -> {
            productRequireRepository.save(v);
        });

    }


    // 转储终止, 终止要货分配数、要货扩展表
    @Listener(topic = "event:fn.crossCompanyTransferNewService.termination")
    private void dumpCacelUpdateAssignQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        Map<String, ProductRequire> requireCache = new HashMap();
        getJO.getJSONArray("item").forEach(item -> {
            JSONObject dumpObj = new JSONObject((Map) item);
            String productId = dumpObj.getString("productId");

            // 查询要货扩展表
            List<ProductRequireExpand> productRequireExpands = productRequireExpandRepository.accordDistributIdAndProId(getJO.getString("id"), productId);
            if (productRequireExpands.isEmpty()) return;

            // 目的：获取要货计量单位方便后面计算
            ProductRequireItem requireItemPro = productRequireItemRepository.findOne(productRequireExpands.get(0).getOriginItemId());

            double qty = this.accordUomChangeQty(dumpObj.getDoubleValue("qty"), requireItemPro.getUom().getId(), dumpObj.getLongValue("uomId")); // 转储数量转换为要货最小单位数量
            AtomicDouble dumpQtyExpandUse = new AtomicDouble(qty); // 转储数量总和
            productRequireExpands.stream()
                    .filter(expand -> {return expand.getAssignQty() - expand.getShipQty() - expand.getCancelQty() > 0;})
                    .forEach(expand2 -> {

                        // 1. 终止要货扩展表数量
                        double requireExpandCanCancelQty = expand2.getAssignQty() - expand2.getShipQty() - expand2.getCancelQty(); // 单个要货实际分配数量
                        double expandCancelQty = requireExpandCanCancelQty > dumpQtyExpandUse.get()?dumpQtyExpandUse.get():requireExpandCanCancelQty;
                        dumpQtyExpandUse.set(dumpQtyExpandUse.get() - expandCancelQty);
                        invoke("stock.productRequireExpandService.updateCancelQty", MapUtil.mapper("distributionId", getJO.getString("id"), "originItemId", expand2.getOriginItemId(), "cancelQty", expandCancelQty));

                        // 2. 修改要货制单数量， ***************【必须要先修改要货制单数量，再修改要货单已分配数量】******************
                        this.updateProductRequireBilling(requireItemPro, getJO.getString("id"), getJO.getString("operateInnerBusinessType"), dumpObj.getString("id"),
                                getJO.getString("operate"), requireItemPro.currentStopQty(expandCancelQty));

                        // 3. 要货单缓存起来
                        if (Objects.isNull(requireCache.get(expand2.getOrigin()))) {
                            requireCache.put(expand2.getOrigin(), productRequireRepository.findOne(expand2.getOrigin()));
                        }

                        // 4. 修改要货分配数量
                        requireCache.get(expand2.getOrigin()).getProductRequireItems().stream().filter(requireI -> {
                            return expand2.getOriginItemId().equals(requireI.getId());
                        }).forEach(requireI2 -> {
                            requireI2.setQtyAssigned(requireI2.getQtyAssigned() + (-1 * expandCancelQty));
                        });

                    });
        });

        // 批量修改要货单
        requireCache.forEach((k, v) -> {
            v.checkComplete();
            v.setLastUpdatedStamp(new Date());
            productRequireRepository.save(v);
        });
    }

    // 根据单位转换数量
    private double accordUomChangeQty(double qty, long currentUomId, long uomId) {
        ProductUom requireUom = productUomRepository.findOne(currentUomId);
        if (!requireUom.isTransferFirst()) {
            ProductUom dumpUom = productUomRepository.findOne(uomId);
            return Math.floor(dumpUom.computeQty(qty, requireUom, true));
        }
        return qty;
    }

    public String accordIdFindFnCustomerId(SimpleRequest request) {
        return productRequireRepository.findOne(request.getJO().getString("id")).getCustomerExpand().getId();
    }

    // 根据 要货id 查询数据
    public Map accordIdFindOne(SimpleRequest request) {
        return MapUtil.mapped(productRequireRepository.findOne(request.getJO().getString("id")));
    }


    // 创建要货单 - 供第三方调用
    public List<ProductRequire> externalCreate(SimpleRequest request) {
        JSONObject data = request.getJO();

        ProductRequireDataConversionImp changeData = AbstractProductRequireDataConversion.init(data.getString("innerBusinessType"));
        List<ProductRequire> requires = changeData.externalDataChangeRequireData(request);

        List<ProductRequire> returnRequire = new ArrayList();
        requires.forEach(require -> {
            SimpleRequest request1 = new SimpleRequest();
            request1.setData(require);
            returnRequire.add(this.create(request1));
        });
        return returnRequire;
    }

    // 老系统调用 - 巴图鲁生成采购 - 获取操作员
    public JSONObject obtainCreator(SimpleRequest request) {
        JSONObject param = request.getJO();
        String origin = param.getString("ORIGIN");
        if (StringUtils.hasText(param.getString("requireId"))) {
            Map creatorInfo = productRequireRepository.obtainCreator(param.getString("requireId"));
            if (creatorInfo.isEmpty()) return new JSONObject();
            origin = creatorInfo.get("CREATOR_ID").toString();
        }
        User user = userRepository.findByOrigin(origin);
        JSONObject returnResult = new JSONObject(MapUtil.mapper("SHLXR", user.getName(), "SHLXRDH", user.getMobileNumber()));
        return returnResult;
    }

    // 外部单据分配要货数，减少要货制单数量
    public void currentAssigentQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        ProductRequireItem requireItem = productRequireItemRepository.findOne(getJO.getString("requireItemId"));

        double minUomFactoryQty = getJO.getDouble("qty");
        if (getJO.containsKey("uomId")) { // 没有计量单位，默认为是最小数量，不需要转换
            ProductUom uom = productUomRepository.findOne(getJO.getLong("uomId"));
            minUomFactoryQty = uom.computeQty(getJO.getDouble("qty"), requireItem.getUom(), true);
        }
        double validQty = requireItem.getCurrentAssigentQty(minUomFactoryQty);

        // 修改要货制单数量
        this.updateProductRequireBilling(requireItem, getJO.getString("operateId"), getJO.getString("operateBusinessType"), getJO.getString("operateItemId"),
                getJO.getString("operateRemark"), -1 * validQty);
    }

    // 外部单据终止，增加要货制单数量
    public void currentStopQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        ProductRequireItem requireItem = productRequireItemRepository.findOne(getJO.getString("requireItemId"));

        double minUomFactoryQty = getJO.getDouble("qty");
        if (getJO.containsKey("uomId")) { // 没有计量单位，默认为是最小数量，不需要转换
            ProductUom uom = productUomRepository.findOne(getJO.getLong("uomId"));
            minUomFactoryQty = uom.computeQty(getJO.getDouble("qty"), requireItem.getUom(), true);
        }

        // 计算可修改要货制单数量
        double validQty = requireItem.currentStopQty(minUomFactoryQty);

        // 修改要货制单数量
        this.updateProductRequireBilling(requireItem, getJO.getString("operateId"), getJO.getString("operateBusinessType"), getJO.getString("operateItemId"),
                getJO.getString("operateRemark"), validQty);
    }

    public void updateProductRequireBilling(ProductRequireItem requireItem, String operateId, String operateBusinessType, String operateItemId, String operateRemark, double changeQty) {
        productAccountService.setProductRequireBilling(requireItem.getProduct(),
                requireItem.getProductRequire().getLocation(), requireItem.getUom(), changeQty,
                operateBusinessType, operateId, operateItemId,
                operateRemark, requireItem.getProductRequire().getLocation().getCompany(), requireItem.getProductRequire().getId());
    }

}


































